package riven.club.asyc;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 陈浩
 * @date 2021/12/7
 */
public class CompletableFutureTest {

    CompletableFutureTest completableFutureTest;

    public static void main(String[] args) {

        long start = System.currentTimeMillis();

        System.out.println();

    }

    @Before
    public void before() {
        completableFutureTest = new CompletableFutureTest();
    }

    @Test
    public void test() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        completableFutureTest.future();
//        completableFutureTest.synchrnize();
        System.out.println(System.currentTimeMillis() - start);
        // 1 2
        // 2036
    }

    @Test
    public void test2() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Beautiful");
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "World");

        CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2, future3);
        combinedFuture.get();
        System.out.println(future1.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
        // Hello
        // Beautiful
        // World
    }

    /**
     * runAsync方法不支持返回值。
     * supplyAsync可以支持返回值。
     */
    private void future() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(this::future1);
        CompletableFuture<String> completableFuture2 = CompletableFuture.supplyAsync(this::future2);
        String combined = Stream.of(completableFuture1, completableFuture2)
                .map(CompletableFuture::join)
                .collect(Collectors.joining(" "));
        System.out.println(combined);
//        CompletableFuture.allOf(completableFuture1, completableFuture2);
    }

    private void synchrnize() {
        future1();
        future2();
    }

    private String future1() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "1";
    }

    private String future2() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "2";
    }


    /**
     * 串行 第二个任务依赖第一个任务的结果
     */
    @Test
    public void test3() throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return completableFutureTest.get1("hello");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        });

        CompletableFuture<String> future = completableFuture.thenApply(s -> {
            try {
                return completableFutureTest.get1(s + " word");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        });
        System.out.println(future.get());
        System.out.println(System.currentTimeMillis() - start);
        // hello word
        // 4036
    }

    private String get1(String s) throws InterruptedException {
        Thread.sleep(2000);
        return s;
    }

    @Test
    public void test4() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
                    try {
                        return completableFutureTest.get1("hello");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return null;
                })
                .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));

        System.out.println(completableFuture.get());
    }


}
